/*
 * Copyright 2008-2009 Daniel Cachapa <cachapa@gmail.com>
 * 
 * This program is distributed under the terms of the GNU General Public Licence Version 3
 * The licence can be read in its entirety in the LICENSE.txt file accompaning this source code,
 * or at: http://www.gnu.org/copyleft/gpl.html
 * 
 * This file is part of WeightWatch.
 *
 * WeightWatch is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * WeightWatch is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with the WeightWatch source code. If not, see
 * <http://www.gnu.org/licenses/>.
 */

package net.cachapa.weightwatch.util;

import java.util.Calendar;
import java.util.Date;

public class MyDate {
	private long time;
	private static final String[] MONTH_NAMES = {"january", "february", "march", "april", "may_long",
		"june", "july", "august", "september", "october", "november", "december"};
	private static final String[] SHORT_MONTH_NAMES = {"jan", "feb", "mar", "apr", "may",
		"jun", "jul", "aug", "sep", "oct", "nov", "dec"};
	private static final long DAY_IN_MILISECONDS = 86400000;
	
	public MyDate() {
		time = System.currentTimeMillis();
	}
	
	public MyDate(long time) {
		this.time = time;
	}

	public MyDate(MyDate date) {
		this.time = date.time;
	}
	
	public MyDate(int day, int month, int year) {
		Calendar calendar = Calendar.getInstance();
		
		// Setting the time to the start of day
		calendar.set(Calendar.HOUR_OF_DAY, 0);
		calendar.set(Calendar.MINUTE, 0);
		calendar.set(Calendar.SECOND, 0);
		calendar.set(Calendar.MILLISECOND, 0);
		
		calendar.set(Calendar.DAY_OF_MONTH, day);
		calendar.set(Calendar.MONTH, month - 1);
		calendar.set(Calendar.YEAR, year);
		time = calendar.getTime().getTime();
	}
	
	public long getTime() {
		return time;
	}
	
	public void setTime(long time) {
		this.time = time;
	}
	
	public int getDay() {
		Calendar cal = Calendar.getInstance();
		cal.setTime(new Date(time));
		return cal.get(Calendar.DAY_OF_MONTH);
	}
	
	public int getMonth() {
		Calendar cal = Calendar.getInstance();
		cal.setTime(new Date(time));
		return cal.get(Calendar.MONTH) + 1;
	}
	
	public int getYear() {
		Calendar cal = Calendar.getInstance();
		cal.setTime(new Date(time));
		return cal.get(Calendar.YEAR);
	}
	
	public int differenceInDays(MyDate date) {
		// First we create an auxiliary date and set it to the same miliseconds
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(new Date(this.time));
		// Then we set the day, month and year on the auxiliary date
		calendar.set(Calendar.DAY_OF_MONTH, date.getDay());
		calendar.set(Calendar.MONTH, date.getMonth()-1);
		calendar.set(Calendar.YEAR, date.getYear());
		// This way we can make the following calculation without having to worry about rounding errors
		return (int)((calendar.getTime().getTime() - this.time) / DAY_IN_MILISECONDS);
	}
	
	public void addDays(int days) {
		time += days * DAY_IN_MILISECONDS;
	}
	
	public void retreatMonth() {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(new Date(time));
		
		int year = getYear();
		int month = getMonth() - 1;
		if (month < 1) {
			year--;
			month = 12;
		}
		
		calendar.set(Calendar.DAY_OF_MONTH, 1);
		calendar.set(Calendar.MONTH, month - 1);
		calendar.set(Calendar.YEAR, year);
		time = calendar.getTime().getTime();
	}
	
	public void advanceMonth() {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(new Date(time));
		
		int year = getYear();
		int month = getMonth() + 1;
		if (month > 12) {
			year++;
			month = 1;
		}
		
		calendar.set(Calendar.DAY_OF_MONTH, 1);
		calendar.set(Calendar.MONTH, month - 1);
		calendar.set(Calendar.YEAR, year);
		time = calendar.getTime().getTime();
	}
	
	public void retreatYear() {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(new Date(time));
		
		calendar.set(Calendar.DAY_OF_MONTH, 1);
		calendar.set(Calendar.MONTH, getMonth() - 1);
		calendar.set(Calendar.YEAR, getYear() - 1);
		time = calendar.getTime().getTime();
	}
	
	public void advanceYear() {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(new Date(time));
		
		calendar.set(Calendar.DAY_OF_MONTH, 1);
		calendar.set(Calendar.MONTH, getMonth() - 1);
		calendar.set(Calendar.YEAR, getYear() + 1);
		time = calendar.getTime().getTime();
	}
	
	public static String getMonthName(int month) {
		return L.l(MONTH_NAMES[month-1]);
	}
	
	public String getMonthName() {
		return L.l(MONTH_NAMES[getMonth()-1]);
	}
	
	public static String getShortMonthName(int month) {
		return L.l(SHORT_MONTH_NAMES[month-1]);
	}
	
	public String getShortMonthName() {
		return L.l(SHORT_MONTH_NAMES[getMonth()-1]);
	}
	
	public boolean isBefore(MyDate other) {
		return this.time < other.getTime();
	}

	public static int getDaysInMonth(int month, int year) {
		switch (month) {
			case 4:
			case 6:
			case 9:
			case 11:
				return 30;
			case 2:
				return year % 4 == 0 && year % 100 != 0 ? 29 : 28;
			default:
				return 31;
		}
	}
	
	public static int getDaysInYear(int year) {
		return year % 4 == 0 && year % 100 != 0 ? 366 : 365;
	}
	
	public static int getWeekday(int day, int month, int year) {
		Calendar calendar = Calendar.getInstance();
		calendar.set(Calendar.DAY_OF_MONTH, day);
		calendar.set(Calendar.MONTH, month - 1);
		calendar.set(Calendar.YEAR, year);
		return calendar.get(Calendar.DAY_OF_WEEK);
	}
	
	int getWeekday() {
		return getWeekday(this.getDay(), this.getMonth(), this.getYear());
	}
	
	public String toString() {
		String dateString = "";
		dateString += this.getDay() + "-";
		dateString += this.getMonthName() + "-";
		dateString += this.getYear();
		return dateString;
	}
	
	public String toShortString() {
		String dateString = "";
		dateString += this.getDay() + ".";
		dateString += this.getShortMonthName() + ".";
		dateString += String.valueOf(this.getYear()).substring(2, 4);
		return dateString;
	}

	public boolean equals(MyDate other) {
		if (this.getDay() == other.getDay() && this.getMonth() == other.getMonth() && this.getYear() == other.getYear())
			return true;
		return false;
	}
}
